package image

import (
	"bytes"
	"encoding/base64"
	"errors"
	"fmt"
	"github.com/golang/freetype"
	"github.com/golang/freetype/truetype"
	"image"
	"image/jpeg"
	"image/png"
	"io/ioutil"
	"micro-grpc-server/library/image/handlers"
	"net/http"
	"os"
	"path"
)

type Handler interface {
	Process(img *image.RGBA) (*image.RGBA, error)
}

type Image struct {
	canvas   *Canvas
	handlers []Handler
	Font     *truetype.Font
}

func NewCanvasImage(canvas *Canvas) *Image {
	im := &Image{
		canvas: canvas,
	}
	return im
}

// 设置字体文件
func (i *Image) ReplaceFont(path string) {
	var (
		fontBytes []byte
		err       error
		font      *truetype.Font
	)

	fontBytes, err = ioutil.ReadFile(path)
	if err != nil {
		panic(fmt.Sprintf("字体文件未找到 -> %s", err.Error()))
	}
	font, err = freetype.ParseFont(fontBytes)
	if err != nil {
		panic(fmt.Sprintf("字体文件加载失败 -> %s", err.Error()))
	}
	i.Font = font
}

// 验证字体文件
func (i *Image) checkFontFile() bool {
	if i.Font != nil {
		return true
	}
	if len(i.canvas.FontFile) == 0 {
		return false
	}
	i.ReplaceFont(i.canvas.FontFile)
	return true
}

// 这个玩意的 x,y 坐标是以左下为原点
// 写入字符串
func (i *Image) WriteString(str string, x int, y int, size float64, lineHeight int, color string, w int, raw int, args StringArgs) (line int, words []handlers.WordLocation) {
	if !i.checkFontFile() {
		panic("请检查字体文件是否正确")
	}

	if w == 0 || raw == 0 {
		return
	}

	words = handlers.ChunkStr(str, x, y, size, lineHeight, w, raw)
	for _, word := range words {
		if word.Word == "" {
			continue
		}
		line += 1
		// 实际上 lineHeight 才是一行的高度 而不是size
		i.handlers = append(i.handlers, &handlers.WriteString{
			Word:       word.Word,
			X:          word.X,
			Y:          word.Y,
			Color:      color,
			Font:       i.Font,
			Size:       size,
			LineHeight: lineHeight,
		})
	}

	fmt.Println(words)
	for _, word := range words {
		if word.Word == "" {
			continue
		}
		if args.Decoration != nil {
			i.handlers = append(i.handlers, &handlers.WriteLine{
				X:       word.X,
				Y:       word.Y,
				Color:   args.Decoration.Color,
				Width:   word.Length - args.Decoration.OffsetX,
				Height:  args.Decoration.Height,
				OffsetX: args.Decoration.OffsetX,
				OffsetY: args.Decoration.OffsetY,
			})
		}
	}

	return line, words
}

// 画直线
func (i *Image) WriteLine(x int, y int, color string, width int, height int, offsetX int, offsetY int) {
	i.handlers = append(i.handlers, &handlers.WriteLine{
		X:       x,
		Y:       y,
		Color:   color,
		Width:   width,
		Height:  height,
		OffsetX: offsetX,
		OffsetY: offsetY,
	})
}

// 写入图片
func (i *Image) WriteImage(path string, x int, y int, width int, height int, circle bool) {
	i.handlers = append(i.handlers, &handlers.WriteImage{
		Path:   path,
		X:      x,
		Y:      y,
		Width:  width,
		Height: height,
		Circle: circle,
	})
}

// 写入文件流 类似微信返回的QrCode
func (i *Image) WriteBuffer(r []byte, x int, y int, width int, height int) {
	i.handlers = append(i.handlers, &handlers.WriteBuffer{
		B:      r,
		X:      x,
		Y:      y,
		Width:  width,
		Height: height,
	})
}

func (i *Image) JoinHandlers(handlers ...Handler) {
	i.handlers = append(i.handlers, handlers...)
}

type Resource struct {
	Name  string
	Write http.ResponseWriter
	Cache bool
}

// 直接返回到接口资源
func (i *Image) WriteToResource(w http.ResponseWriter) error {
	imageResource, err := i.processHandlers()
	if err != nil {
		return err
	}
	w.Header().Set("Content-Type", "image/png")
	return png.Encode(w, imageResource)
}

// 返回生成的文件地址
func (i Image) WriteToFile(r Resource) (filePath string, err error) {
	var imageResource *image.RGBA
	imageResource, err = i.processHandlers()

	filePath = "/tmp/" + r.Name
	fileWrite, err := os.Create(filePath)
	if err != nil {
		return filePath, errors.New("create image failed. ")
	}

	ext := path.Ext(r.Name)
	switch ext {
	case ".png":
		err = png.Encode(fileWrite, imageResource)
	case ".jpg":
		err = jpeg.Encode(fileWrite, imageResource, &jpeg.Options{Quality: 100})
	default:
		err = errors.New("不支持的图片格式")
	}
	if err != nil {
		return "", errors.New("create image failed. " + err.Error())
	}

	return
}

// 返回base64
func (i *Image) WriteToBase64() (b string, err error) {
	var (
		m   image.Image
		buf bytes.Buffer
	)

	m, err = i.processHandlers()
	if err != nil {
		return b, err
	}

	err = png.Encode(&buf, m)
	if err != nil {
		return b, errors.New("生成失败" + err.Error())
	}

	return base64.StdEncoding.EncodeToString(buf.Bytes()), nil
}

// 返回bytes
func (i *Image) WriteToBytes() ([]byte, error) {
	var (
		m   image.Image
		buf bytes.Buffer
		err error
	)

	m, err = i.processHandlers()
	if err != nil {
		return nil, err
	}

	err = png.Encode(&buf, m)
	if err != nil {
		return nil, errors.New("生成失败" + err.Error())
	}

	return buf.Bytes(), nil
}

func (i *Image) processHandlers() (img *image.RGBA, err error) {
	// 先载入画布
	if img, err = i.canvas.GenerateDrawCanvas(); err != nil {
		return img, err
	}

	for _, h := range i.handlers {
		if img, err = h.Process(img); err != nil {
			return img, err
		}
	}
	return
}
